package gitobject;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Date;

public class Commit extends GitObject {

    public static class Builder {
        Commit commit = new Commit();

        public Commit build() {
            try {
                var md = MessageDigest.getInstance("SHA-1");
                if (commit.parent != null) {
                    md.update(commit.parent);
                }
                md.update(commit.tree);
                md.update(commit.committer.getBytes(StandardCharsets.UTF_8));
                md.update(commit.author.getBytes(StandardCharsets.UTF_8));
                md.update(commit.message.getBytes(StandardCharsets.UTF_8));
                ByteBuffer time_bytearray = ByteBuffer.allocate(Long.BYTES);
                time_bytearray.putLong(commit.time.getTime());
                md.update(time_bytearray.array());
                commit.key = md.digest();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            return commit;
        }

        /**
         * @param key 哈希字节数组
         * @return 为Commit类对象的key属性赋值
         */
        public Builder parent(byte[] key) {
            commit.parent = key;
            return this;
        }

        /**
         * @param author 作者
         * @return 为Commit类对象的author属性赋值
         */
        public Builder author(String author) {
            commit.author = author;
            return this;
        }

        /**
         * @param msg 备注信息
         * @return 为Commit类对象的msg属性赋值
         */
        public Builder message(String msg) {
            commit.message = msg;
            return this;
        }

        /**
         * @param key 哈希字节数组
         * @return 为Commit类对象的tree属性赋值
         */
        public Builder tree(byte[] key) {
            commit.tree = key;
            return this;
        }

        /**
         * @param time 时间戳
         * @return 为Commit类对象的time属性赋值
         */
        public Builder time(Date time) {
            commit.time = time;
            return this;
        }

        /**
         * @param committer 提交者
         * @return 为Commit类对象的committer属性赋值
         */
        public Builder committer(String committer) {
            commit.committer = committer;
            return this;
        }
    }

    byte[] parent;
    String author;
    String message;
    byte[] tree;
    String committer;
    Date time;

    Commit() {
        type = Type.Commit;
    }

    /**
     * @return 返回Commit类对象的作者
     */
    public String getAuthor() {
        return author;
    }

    /**
     * @return 返回Commit类对象的上一次提交的哈希值
     */
    public byte[] getParent() {
        return parent;
    }

    /**
     * @return 返回Commit类对象的备注信息
     */
    public String getMessage() {
        return message;
    }

    /**
     * @return 返回Commit类对象的时间戳
     */
    public Date getTime() {
        return time;
    }

    /**
     * @return 返回Commit类对象指向的Tree类对象的哈希值
     */
    public byte[] getTree() {
        return tree;
    }

    /**
     * 对Commit类对象写入额外信息
     *
     * @param out
     * @throws IOException
     */
    @Override
    public void writeExtendInfo(DataOutputStream out) throws IOException {
        if (parent != null) {
            out.writeBoolean(true);
            out.write(parent, 0, 20);
        } else {
            out.writeBoolean(false);
        }
        out.writeUTF(author);
        out.writeUTF(committer);
        out.writeUTF(message);
        out.writeLong(time.getTime());
        out.write(tree, 0, 20);
    }

    /**
     * 从Commit类对象读取额外信息
     *
     * @param in
     * @throws IOException
     */
    @Override
    public void readExtendInfo(DataInputStream in) throws IOException {
        boolean hasParent = in.readBoolean();
        if (hasParent) {
            parent = in.readNBytes(20);
        } else {
            parent = null;
        }
        author = in.readUTF();
        committer = in.readUTF();
        message = in.readUTF();
        time = new Date(in.readLong());
        tree = in.readNBytes(20);
    }
}
